#include "UartDriver.h"

static UartDriver UartObj[USE_UART_NUM];

#if USE_UART_NUM > 0 & defined DEBUG

///重定向c库函数printf到USART1
int fputc(int ch, FILE *f)
{
#ifdef DEBUG_UART
	/* 发送一个字节数据到USART1 */
	DEBUG_UART->DR = (uint8_t)ch; //重定向到外部串口中
//	USART_SendData(USART1, (uint8_t) ch);
		
	/* 等待发送完毕 */
	while ((DEBUG_UART->SR & UART_FLAG_TC) == RESET) ;
//	while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) ;
#endif // DEBUG_UART

	ITM_SendChar(ch);	//重定向到debug viewer
	return (ch);
}

#ifdef DEBUG_UART
///重定向c库函数scanf到USART1
int fgetc(FILE *f)
{
	/* 等待串口1输入数据 */
	while ((DEBUG_UART->SR & UART_FLAG_RXNE) == RESET) ;
//	while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET) ;

	return (int)DEBUG_UART->DR;
//	return (int)USART_ReceiveData(USART1);
}
#endif // DEBUG_UART
#endif // DEBUG

/*
********************************************************************************
** 描述 :串口发送完成中断回调函数. 所有串口发送完成中断回调函数都到这里，因此要判断是哪个串口
********************************************************************************/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	for (size_t i = 0; i < USE_UART_NUM; i++)
	{
		if (huart == UartObj[i].phuart)
		{
#ifdef osFeature_Semaphore
			if (UartObj[i].TxCpltSem != NULL)
				osSemaphoreRelease(UartObj[i].TxCpltSem);
#else
			if (UartObj[i].TxCpltSem == 0)
				UartObj[i].TxCpltSem = 1; //通知已发送完成
#endif // osFeature_Semaphore
			return;
		}
	}
}

/*
********************************************************************************
** 描述 :启动发送数据
** 返回 :0:成功，-1--访问UART故障，其它--见stm32fxxx_hal_uart.h中UART Error Code的定义
********************************************************************************/
int UD_Transmit(UartDriver * obj/*[I]指向驱动对象*/,
	         unsigned char *pTxBuf/*[I]指向发送数据存放位置*/, 
	         unsigned int size/*[I]传输字节数*/)
{
	if (obj->phuart->hdmatx == NULL)
	{
		//由CubeMX配置决定
		if (HAL_UART_Transmit_IT(obj->phuart, pTxBuf, size) != HAL_OK)
		{
			return -1;
		}
	}
	else
	{
		if (HAL_UART_Transmit_DMA(obj->phuart, pTxBuf, size) != HAL_OK)
		{
			//启动发送
			return -1;
		}
	}

	//等待传输结束
#ifdef osFeature_Semaphore
	if (obj->TxCpltSem != NULL)
		osSemaphoreWait(obj->TxCpltSem, osWaitForever);
#else
	if (obj->TxCpltSem == -1)
	{
		return 0;
	}
	while (obj->TxCpltSem == 0) ;
	obj->TxCpltSem = 0; //复位发送完成标志
#endif // osFeature_Semaphore

	return 0;//obj->phuart->ErrorCode;
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
	for (size_t i = 0; i < USE_UART_NUM; i++)
	{
		if (huart == UartObj[i].phuart)
		{
			//重新开始接收
			#ifdef	UART_USE_HAL_IDLE_INT	//#2022/10/27#增加
			if (huart->hdmarx != NULL)
				HAL_UARTEx_ReceiveToIdle_DMA(huart, huart->pRxBuffPtr, huart->RxXferSize);
			else
				HAL_UARTEx_ReceiveToIdle_IT(huart, huart->pRxBuffPtr, huart->RxXferSize);
			#else
			if (huart->hdmarx != NULL)
				HAL_UART_Receive_DMA(huart, huart->pRxBuffPtr, huart->RxXferSize);
			else
				HAL_UART_Receive_IT(huart, huart->pRxBuffPtr, huart->RxXferSize);
			#endif
			UartObj[i].old_pos = 0;
			break;
		}
	}
}

#ifdef UART_USE_HAL_IDLE_INT	//使用HAL的空闲驱动
/*
********************************************************************************
** 函数名称 :	HAL_UART_IdleCallback	串口接收空闲中断回调函数
** 描    述 :	利用收到空闲帧来断帧.注意当完成一半和空闲都会调用,完成且无论空闲与否只调用1次.
** 输入参数 :	UART_HandleTypeDef *huart		指向发生空闲帧的串口句柄
** 返    回 :	无
********************************************************************************/
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	for (size_t i = 0; i < USE_UART_NUM; i++)
	{
		if (huart == UartObj[i].phuart)
		{
			if (Size != UartObj[i].old_pos)	//如果相等代表循环溢出或没有接收到数据
			{
				//#2.#从接收缓冲队列中取出接收到的数据
				//#2.1#取出接收缓冲区首址
				uint8_t *pRxBuf = huart->pRxBuffPtr; //(uint8_t*)UartObj[i].phuart->hdmarx->Instance->M0AR;
				if (Size > UartObj[i].old_pos)	//接收到的数据在已取出数据位置的下方
				{
					int num = Size - UartObj[i].old_pos;
					while (num-- != 0)
					{
						UartObj[i].pFrBuf[UartObj[i].FrLen++] = pRxBuf[UartObj[i].old_pos++];
					}
				}
				else	//接收到的数据在已取出数据位置的下方和上方
				{
					//下方接收到的数据个数
					int num = huart->RxXferSize - UartObj[i].old_pos; //UartObj[i].BufSize - UartObj[i].old_pos;
					while (num-- != 0)
					{
						UartObj[i].pFrBuf[UartObj[i].FrLen++] = pRxBuf[UartObj[i].old_pos++];
					}
					//接收上方数据
					UartObj[i].old_pos = 0;
					while (Size-- != 0)
					{
						UartObj[i].pFrBuf[UartObj[i].FrLen++] = pRxBuf[UartObj[i].old_pos++];
					}
				}
				//#3.#通知有1帧数据
#ifdef osFeature_Semaphore
				osSemaphoreRelease(UartObj[i].RxIdleSem);
#else
				UartObj[i].RxIdleSem = true;
#endif // osFeature_Semaphore
			}
			return;
		}
	}
}
#elif defined UART_USE_IDLE_INT	//==使用自己写的空闲中断驱动
/*
********************************************************************************
** 描    述 :	中断函数修改范例
********************************************************************************/
#if 0
void USART1_IRQHandler(void)
{
	/* USER CODE BEGIN USART1_IRQn 0 */
	  //因HAL_UART_IRQHandler没有对空闲中断处理故加在这处理
	int tmp1 = __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE);
	int tmp2 = __HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_IDLE);
	if ((tmp1 != RESET) && (tmp2 != RESET))
	{ 
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);
		HAL_UART_IdleCallback(&huart1);
		return;
	}

	/* USER CODE END USART1_IRQn 0 */
	HAL_UART_IRQHandler(&huart1);
	/* USER CODE BEGIN USART1_IRQn 1 */

	/* USER CODE END USART1_IRQn 1 */
}
#endif

//针对接收一帧中绝对只有一个空闲中断(连续发送一帧)而且发生在帧结束后的帧
__weak void HAL_UART_IdleCallback(UART_HandleTypeDef *huart)
{
	for (size_t i = 0; i < USE_UART_NUM; i++)
	{
		if (huart == UartObj[i].phuart)
		{
			//#1.#获得接收队列中已接收到数据的末位
			int Size = huart->RxXferSize - __HAL_DMA_GET_COUNTER(huart->hdmarx);
			if (Size != UartObj[i].old_pos)	//如果相等代表循环溢出或没有接收到数据
			{
				//#2.#从接收缓冲队列中取出接收到的数据
				//#2.1#取出接收缓冲区首址
				uint8_t *pRxBuf = huart->pRxBuffPtr;//(uint8_t*)UartObj[i].phuart->hdmarx->Instance->M0AR;
				if (Size > UartObj[i].old_pos)	//接收到的数据在已取出数据位置的下方
				{
					int num = Size - UartObj[i].old_pos;
					while (num-- != 0)
					{
						UartObj[i].pFrBuf[UartObj[i].FrLen++] = pRxBuf[UartObj[i].old_pos++];
					}
				}
				else	//接收到的数据在已取出数据位置的下方和上方
				{
					//下方接收到的数据个数
					int num = huart->RxXferSize - UartObj[i].old_pos; //UartObj[i].BufSize - UartObj[i].old_pos;
					while (num-- != 0)
					{
						UartObj[i].pFrBuf[UartObj[i].FrLen++] = pRxBuf[UartObj[i].old_pos++];
					}
					//接收上方数据
					UartObj[i].old_pos = 0;
					while (Size-- != 0)
					{
						UartObj[i].pFrBuf[UartObj[i].FrLen++] = pRxBuf[UartObj[i].old_pos++];
					}
				}
				//#3.#通知有1帧数据
#ifdef osFeature_Semaphore
				osSemaphoreRelease(UartObj[i].RxIdleSem);
#else
				UartObj[i].RxIdleSem = 1;
#endif // osFeature_Semaphore
			}
			return;
		}
	}
}
#else	//UART_USE_DMA_INT			//定义使用DMA完成中断驱动
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	for (size_t i = 0; i < USE_UART_NUM; i++)
	{
		if (huart == UartObj[i].phuart)
		{
			UartObj[i].pFrBuf = huart->pRxBuffPtr + huart->RxXferSize / 2;
			osSemaphoreRelease(UartObj[i].RxIdleSem);
			PRINT("rx cplt\r\n");
		}
	}
}
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
{
	for (size_t i = 0; i < USE_UART_NUM; i++)
	{
		if (huart == UartObj[i].phuart)
		{
			UartObj[i].pFrBuf = huart->pRxBuffPtr;
			osSemaphoreRelease(UartObj[i].RxIdleSem);
			PRINT("rx half\r\n");
		}		
	}
}
#endif

//描述: 注册串口对象
//返回: 0:成功；1:重复注册已经注册过了；-1:注册空间已经用完，需调整USE_UART_NUM数量。
int UD_Register(
	UartDriver **obj			/*[IO]指向驱动对象*/,
	UART_HandleTypeDef *huart	/*[I]指向Uart句柄*/,
	unsigned char *rxBuf		/*[I]接收缓冲区*/, 
	unsigned char *frBuf		/*[I]帧数据缓冲区*/,
	unsigned int bufSize		/*[I]缓冲区大小*/)
{
	for (size_t i = 0; i < USE_UART_NUM; i++)
	{
		if (UartObj[i].phuart == huart)
		{
			*obj = &UartObj[i];
			return 1;
		}
		if (UartObj[i].phuart == NULL)
		{
			UartObj[i].phuart = huart;
			UartObj[i].pFrBuf = frBuf;
			UartObj[i].old_pos = 0;
			*obj = &UartObj[i];
#ifdef UART_USE_HAL_IDLE_INT
			if (huart->hdmarx != NULL)
				HAL_UARTEx_ReceiveToIdle_DMA(huart, rxBuf, bufSize);
			else
				HAL_UARTEx_ReceiveToIdle_IT(huart, rxBuf, bufSize);
#elif defined UART_USE_IDLE_INT
			if (huart->hdmarx != NULL)
				HAL_UART_Receive_DMA(huart, rxBuf, bufSize);
			else
				HAL_UART_Receive_IT(huart, rxBuf, bufSize);
			__HAL_UART_CLEAR_IDLEFLAG(huart);
			__HAL_UART_ENABLE_IT(huart, UART_IT_IDLE);
#else	//UART_USE_DMA_INT			//定义使用DMA完成中断驱动
			//采用循环dma接收,half/cplt/err和timeout中断
			if (huart->hdmarx != NULL)
				HAL_UART_Receive_DMA(huart, rxBuf, bufSize);
			else
				HAL_UART_Receive_IT(huart, rxBuf, bufSize);
#endif
			return 0;
		}
	}
	return -1;
}
//描述: 对注册过的串口对象成员变量初始化
void UD_Init(
	UartDriver	*obj	 /*[I]注册过的串口对象*/,
	Sem_Def	txSem		 /*[I]发送信号量,等待Uart发送完成否?-1:不等, 其它:等*/,
	Sem_Def	rxSem		 /*[I]接收信号量*/,
	int		readTimeout	 /*[I]读取数据超时时间ms*/,	
	int		idleInterval /*[I]判断空闲时间间隔ms*/)
{
#ifdef osFeature_Semaphore
	obj->TxCpltSem = txSem;
	if (txSem != NULL)
		osSemaphoreWait(txSem, 100);
	obj->RxIdleSem = rxSem;
	osSemaphoreWait(rxSem, 100);
#else
	obj->TxCpltSem = txSem == -1 ? -1 : 0;
	obj->RxIdleSem = rxSem;
#endif // osFeature_Semaphore

	obj->ReadTimeout = readTimeout;
	obj->IdleInterval = idleInterval;
	obj->FrLen = 0;
}

//描述: 读取1帧数据发生超时回调函数
__weak void UD_ReadTimeoutCallBack(UartDriver *obj /*[I]注册过的串口对象*/)
{
}
//描述: 通知调用者"我还活着"--运行正常
__weak void UD_NoticeAliveCallBack(UartDriver *obj /*[I]注册过的串口对象*/)
{
}
//描述: 接收由IdleInterval(空闲间隔时间)给定断帧的数据, 防止1帧中有2个以上的空闲位出现
//返回: 帧数据长度
int UD_ReadFrameData(UartDriver *obj /*[I]注册过的串口对象*/)
{
#ifdef osFeature_Semaphore
	while (true)
	{
		while (osSemaphoreWait(obj->RxIdleSem, obj->ReadTimeout) != HAL_OK)
		{
			UD_ReadTimeoutCallBack(obj);
		}
		//可能是接收完成1半,或完成,或空闲中断
		UD_NoticeAliveCallBack(obj);
		while (true)
		{
			volatile uint16_t old_size = __HAL_DMA_GET_COUNTER(obj->phuart->hdmarx);
			if (osSemaphoreWait(obj->RxIdleSem, obj->IdleInterval) == HAL_OK) continue; //可能是接收完成1半,或完成,或空闲中断
			//超时--空闲间隔时间到
			if (__HAL_DMA_GET_COUNTER(obj->phuart->hdmarx) == old_size) //无新数据到达说明刚才是空闲中断
			{
				int len = obj->FrLen; //接收到的数据位置没变化--帧结束
				obj->FrLen = 0; //准备接受下一帧
				return len;
			}
			break; //有数据变化说明刚才是完成1半,或完成中断,返回等空闲中断
		}
		//
	}
#else
	uint32_t t = HAL_GetTick() + obj->ReadTimeout;
	while (obj->RxIdleSem == 0)
	{
		if ((int)(HAL_GetTick() - t) >= 0)
		{
			//发生超时
			t += obj->ReadTimeout;
			UD_ReadTimeoutCallBack(obj);
		}
	}
	while (1)
	{
		obj->RxIdleSem = 0; //复位空闲中断标志
		volatile uint16_t old_size = __HAL_DMA_GET_COUNTER(obj->phuart->hdmarx);
		t = HAL_GetTick() + obj->IdleInterval;
		UD_NoticeAliveCallBack(obj);
		while (obj->RxIdleSem == 0)
		{
			if ((int)(HAL_GetTick() - t) >= 0)
			{
				//空闲间隔时间到
				if (__HAL_DMA_GET_COUNTER(obj->phuart->hdmarx) == old_size)
				{
					int len = obj->FrLen;//接收到的数据位置没变化--帧结束
					obj->FrLen = 0;
					return len;
				}
				break;
			}
		}
	}
#endif
}

//描述: 字节数组到16位整形数的转换(小端系统)
void UD_BytesToShort(void *sDat, const void *buf)
{
	uint16_t *pDst = (uint16_t*)sDat;
	uint8_t *pSrc = (uint8_t*)buf;
	*pDst = pSrc[0] | (pSrc[1] << 8);
}
//描述: 从字节缓冲区中取出16位整形数(小端系统)
short UD_GetShort(const void *buf)
{
	uint8_t *pSrc = (uint8_t*)buf;
	return pSrc[0] | (pSrc[1] << 8);
}
//描述: 获得给定的16位整形数所对应的数组(小端系统)
void UD_ShortToBytes(void *buf, short sDat)
{
	uint8_t *pDst = (uint8_t*)buf;
	uint8_t *pSrc = (uint8_t*)&sDat;
	*pDst++ = *pSrc++;
	*pDst++ = *pSrc++;
}
//描述: 字节数组到16位整形数的转换(大端系统)
void UD_BytesToShort_REV(void *sDat, const void *buf)
{
	uint16_t *pDst = (uint16_t*)sDat;
	uint8_t *pSrc = (uint8_t*)buf;
	*pDst = pSrc[1] | (pSrc[0] << 8);
}
//描述: 从字节缓冲区中取出16位整形数(大端系统)
short UD_GetShort_REV(const void *buf)
{
	uint8_t *pSrc = (uint8_t*)buf;
	return pSrc[1] | (pSrc[0] << 8);
}
//描述: 获得给定的16位整形数所对应的数组(大端系统)
void UD_ShortToBytes_REV(void *buf, short sDat)
{
	uint8_t *pDst = (uint8_t*)buf;
	uint8_t *pSrc = (uint8_t*)&sDat;
	*pDst++ = pSrc[1];
	*pDst++ = pSrc[0];
}

//描述: 字节数组到32位整形数的转换(小端系统)
void UD_BytesToInt(void *iDat, const void *buf)
{
	uint8_t *pSrc = (uint8_t*)buf;
	uint32_t *ui = (uint32_t*)iDat;
	*ui = pSrc[0] | (pSrc[1] << 8) | (pSrc[2] << 16) | (pSrc[3] << 24);
//	uint8_t *pInt = (uint8_t*)iDat;
//	*pInt++ = *pSrc++;
//	*pInt++ = *pSrc++;
//	*pInt++ = *pSrc++;
//	*pInt++ = *pSrc++;
}
//描述: 从字节缓冲区中取出32位整形数(小端系统)
int UD_GetInt(const void *buf)
{
	uint8_t *pSrc = (uint8_t*)buf;
	return pSrc[0] | (pSrc[1] << 8) | (pSrc[2] << 16) | (pSrc[3] << 24);
}
//描述: 32位整形数到字节数组的转换(小端系统)
//描述: 获得给定的32位整形数所对应的数组(小端系统)
void UD_IntToBytes(const void *buf, int iDat)
{
	uint8_t *pDst = (uint8_t*)buf;
	pDst[0] = iDat;
	pDst[1] = iDat >> 8;
	pDst[2] = iDat >> 16;
	pDst[3] = iDat >> 24;
//	uint8_t *pInt = (uint8_t*)&iDat;
//	*pDst++ = *pInt++;
//	*pDst++ = *pInt++;
//	*pDst++ = *pInt++;
//	*pDst++ = *pInt++;
}
//描述: 字节数组到32位整形数的转换(大端系统)
void UD_BytesToInt_REV(void *iDat, const void *buf)
{
	uint8_t *pSrc = (uint8_t*)buf;
	uint32_t *ui = (uint32_t*)iDat;
	*ui = pSrc[3] | (pSrc[2] << 8) | (pSrc[1] << 16) | (pSrc[0] << 24);
	//	uint8_t *pInt = (uint8_t*)iDat;
	//	*pInt++ = *pSrc++;
	//	*pInt++ = *pSrc++;
	//	*pInt++ = *pSrc++;
	//	*pInt++ = *pSrc++;
}
//描述: 从字节缓冲区中取出32位整形数(小端系统)
int UD_GetInt_REV(const void *buf)
{
	uint8_t *pSrc = (uint8_t*)buf;
	return pSrc[3] | (pSrc[2] << 8) | (pSrc[1] << 16) | (pSrc[0] << 24);
}
//描述: 32位整形数到字节数组的转换(小端系统)
//描述: 获得给定的32位整形数所对应的数组(小端系统)
void UD_IntToBytes_REV(const void *buf, int iDat)
{
	uint8_t *pDst = (uint8_t*)buf;
//	pDst[0] = iDat;
//	pDst[1] = iDat >> 8;
//	pDst[2] = iDat >> 16;
//	pDst[3] = iDat >> 24;
	uint8_t *pInt = (uint8_t*)&iDat;
	*pDst++ = pInt[3];
	*pDst++ = pInt[2];
	*pDst++ = pInt[1];
	*pDst++ = pInt[0];
}

//描述: 字节数组到32位浮点数的转换(小端系统)
void UD_BytesToFloat(void *fDat, const void *buf)
{
	uint8_t *pFp = (uint8_t*)fDat;
	uint8_t *pSrc = (uint8_t*)buf;
	*pFp++ = *pSrc++;
	*pFp++ = *pSrc++;
	*pFp++ = *pSrc++;
	*pFp++ = *pSrc++;
}
//描述: 从字节缓冲区中取出32位浮点数(小端系统)
float UD_GetFloat(const void *buf)
{
	float fData;
	UD_BytesToFloat(&fData, buf);
	return fData;
}
//描述: 获得给定的32位浮点数所对应的数组(小端系统)
void UD_FloatToBytes(void *buf, float fDat)
{
	uint8_t *pFp = (uint8_t*)&fDat;
	uint8_t *pDst = (uint8_t*)buf;
	*pDst++ = *pFp++;
	*pDst++ = *pFp++;
	*pDst++ = *pFp++;
	*pDst++ = *pFp++;
}

//描述: 字节数组到64位浮点数的转换(小端系统)
void UD_BytesToDouble(void *dDat, const void *buf)
{
	uint8_t *pDst = (uint8_t*)dDat;
	uint8_t *pSrc = (uint8_t*)buf;
	for (size_t i = 0; i < 8; i++)
	{
		*pDst++ = *pSrc++;
	}
}
//描述: 从字节缓冲区中取出64位浮点数(小端系统)
double UD_GetDouble(const void *buf)
{
	double dData;
	UD_BytesToDouble(&dData, buf);
	return dData;
}
//描述: 获得给定的64位浮点数所对应的数组(小端系统)
void UD_DoubleToBytes(void *buf, double dDat)
{
	uint8_t *pDst = (uint8_t*)buf;
	uint8_t *pSrc = (uint8_t*)&dDat;
	for (size_t i = 0; i < 8; i++)
	{
		pDst[i] = pSrc[i];
	}
}
